package com.example.db;

import android.content.Context;
import android.content.SharedPreferences;

import com.alibaba.fastjson.JSON;
import com.example.im.LoginActivity;
import com.example.im.MainActivity;
import com.example.model.Friends;
import com.example.model.Msg;
import com.example.model.User;
import com.example.util.MyUtil;
import com.example.websocket.MyWebSocketClient;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;

import io.netty.util.internal.StringUtil;

public class CommonData implements Serializable {
    public static CommonData commonData = new CommonData();
    private static final String COMMON_DATA_SP_NAME = "COMMON_DATA";
    private MyWebSocketClient webSocket;
    public Map<String, User> userDb = new HashMap<>();
    public Map<String, Map<String, List<Msg>>> msgDb = new HashMap<>();
    public Map<String, Map<String, Friends>> friendDb = new HashMap<>();
    private boolean isLogin;//登录状态
    private User user;//登录用户
    private Friends chatFriend;

    public static CommonData getCommonData() {
        return commonData;
    }

    public static void setCommonData(CommonData commonData) {
        CommonData.commonData = commonData;
    }

    public MyWebSocketClient getWebSocket() {
        return webSocket;
    }

    public void setWebSocket(MyWebSocketClient webSocket) {
        this.webSocket = webSocket;
    }

    public Map<String, User> getUserDb() {
        return userDb;
    }

    public void setUserDb(Map<String, User> userDb) {
        this.userDb = userDb;
    }

    public Map<String, Map<String, List<Msg>>> getMsgDb() {
        return msgDb;
    }

    public void setMsgDb(Map<String, Map<String, List<Msg>>> msgDb) {
        this.msgDb = msgDb;
    }

    public Map<String, Map<String, Friends>> getFriendDb() {
        return friendDb;
    }

    public void setFriendDb(Map<String, Map<String, Friends>> friendDb) {
        this.friendDb = friendDb;
    }


    public synchronized static CommonData readData(Context context) {
        SharedPreferences sp = context.getSharedPreferences(COMMON_DATA_SP_NAME, Context.MODE_PRIVATE);
        String dataStr = sp.getString(COMMON_DATA_SP_NAME, "");
        if ("".equals(dataStr)) {
            return commonData;
        }
        commonData = JSON.parseObject(dataStr, CommonData.class);
        return commonData;
    }

    public synchronized static void writeData(Context context) {
        if (commonData == null) {
            return;
        }
        SharedPreferences sp = context.getSharedPreferences(COMMON_DATA_SP_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor edit = sp.edit();
        String dataStr = JSON.toJSONString(commonData);
        edit.putString(COMMON_DATA_SP_NAME, dataStr);
        edit.apply();
    }


    public static User getDbUser(String name) {
        return commonData.userDb.get(name);
    }
    public static User getDbUserById(int id) {
        return commonData.userDb.values().stream().filter(u -> Objects.equals(u.getId(), id)).findFirst().orElse(null);
    }
    public static List<Msg> getDbMsg(String curUser, String talkUser) {
        Map<String, List<Msg>> msgMap = commonData.msgDb.get(curUser);
        if (null == msgMap) {
            return new ArrayList<>();
        }
        List<Msg> msgs = msgMap.get(talkUser);
        if (msgs == null) {
            return new ArrayList<>();
        }
        msgs.sort(Comparator.comparing(Msg::getSendTime));
        return msgs;
    }
    public static Friends getDbFriend(String curUserName, String friendName) {
        Map<String, Friends> fMap = commonData.friendDb.get(curUserName);
        if (null == fMap) {
            return null;
        }
        return fMap.get(friendName);
    }

    public static List<Friends> getDbFriendList(String curName) {
        Map<String, Friends> fMap = commonData.friendDb.get(curName);
        if (null == fMap) {
            return new ArrayList<>();
        }
        ArrayList<Friends> friends = new ArrayList<>();
        fMap.forEach((k,v) -> {
            friends.add(v);
        });
        return friends;
    }
    public static List<User> getDbUserList(String curName) {
        Map<String, User> uMap = commonData.userDb;
        if (null == uMap) {
            return new ArrayList<>();
        }
        ArrayList<User> userList = new ArrayList<>();
        uMap.forEach((k,v) -> {
            userList.add(v);
        });
        return userList;
    }
    public static boolean delDbFriend(User cur, Friends f) {
        if (cur == null || f == null) {
            return false;
        }
        Map<String, Friends> fMap = commonData.friendDb.computeIfAbsent(cur.getName(), k -> new HashMap<>());
        Friends friends = fMap.get(f.getName());
        if (null != friends) {
            fMap.remove(f.getName());
            return true;
        }
        return false;
    }
    public static boolean addDbFriend(User cur, User f) {
        if (cur == null || f == null) {
            return false;
        }
        // 如果没有就新建，有则覆盖内容（更新）
        Map<String, Friends> fMap = commonData.friendDb.computeIfAbsent(cur.getName(), k -> new HashMap<>());
        Friends friends = fMap.get(f.getName());
        Friends newF = null == friends ? new Friends() : friends;
        newF.setId(-1);
        newF.setStatus(1);
        newF.setUid(cur.getId());
        newF.setFid(f.getId());
        newF.setName(f.getName());

//            if(getDbMsg(cur.getName(), f.getName()).stream().skip(getDbMsg(cur.getName(), f.getName()).size()-1).findFirst().orElse(null).getMsg()!=null){
//                newF.setLatestMsg(getDbMsg(cur.getName(),f.getName()).stream().reduce((first,second)->second).orElse(null).getMsg());
//            }else {
//                newF.setLatestMsg(null);
//            }
        newF.setLatestMsg(null);
        fMap.put(f.getName(), newF);
        return true;
    }
    private String token;

    /**
     * 退出登录
     * @param context
     */
    public static void logout(Context context) {
        MyUtil.exeUrlTask(context,
                () -> MyUtil.getReqParam("/user/logout", null),
                (res) -> {
                    // 退出成功
                    commonData.setLogin(false);
                    commonData.setUser(null);
                    commonData.setToken(null);
                    writeData(context);
                    //切换到登录页面
                    MyUtil.changeActivity(context, LoginActivity.class,false);
                },
                (res) -> {
                    // 退出失败(可以考虑仅退出本地）
                    MyUtil.toast(context, "未知错误：无法退出账号");
                });
    }

    /**
     * 添加发送的消息到数据库
     * @param curName
     * @param talker
     * @param msg
     */
    public static boolean addDbMsg(String curName, String talker, Msg msg) {
        try {
            Map<String, List<Msg>> db = commonData.msgDb.computeIfAbsent(curName, name -> new HashMap<>());
            List<Msg> list = db.computeIfAbsent(talker, name -> new ArrayList<>());
            Msg oldMsg = list.stream().filter(m -> m.getMid() == msg.getMid()).findFirst().orElse(null);
            if (oldMsg == null) {
                list.add(msg);
            } else {
                oldMsg.setMsg(msg.getMsg());
                oldMsg.setSendTime(msg.getSendTime());
                oldMsg.setMid(msg.getMid());
                oldMsg.setFid(msg.getFid());
                oldMsg.setUid(msg.getUid());
                oldMsg.setStatus(msg.isStatus());
                oldMsg.setType(msg.getType());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public String getToken() {
        return StringUtil.isNullOrEmpty(token) ? "none" : token;
    }

    public void setToken(String token) {
        this.token = token;
    }



    public Friends getChatFriend() {
        return chatFriend;
    }

    public void setChatFriend(Friends chatFriend) {
        this.chatFriend = chatFriend;
    }

    public boolean isLogin() {
        return isLogin;
    }

    public void setLogin(boolean login) {
        isLogin = login;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getLoginUserId() {
        return user == null ? null : user.getId();
    }

    public String getLoginUserName() {
        return user == null ? null : user.getName();
    }
}
